ajax 异步上传图片例子
/** * Ajax upload * Project page - http://valums.com/ajax-upload/ * Copyright (c) 2008 Andris Valums, http://valums.com * Licensed under the MIT license (http://valums.com/mit-license/) * Version 3.5 (23.06.2009) *//** * Changes from the previous version: * 1. Added better JSON handling that allows to use 'application/javascript' as a response * 2. Added demo for usage with jQuery UI dialog * 3. Fixed IE "mixed content" issue when used with secure connections * * For the full changelog please visit: * http://valums.com/ajax-upload-changelog/ */(function(){var d = document, w = window;/** * Get element by id */function get(element){if (typeof element == "string")element = d.getElementById(element);return element;}/** * Attaches event to a dom element */function addEvent(el, type, fn){if (w.addEventListener){el.addEventListener(type, fn, false);} else if (w.attachEvent){var f = function(){ fn.call(el, w.event);};el.attachEvent('on' type, f)}}/** * Creates and returns element from html chunk */var toElement = function(){var div = d.createElement('div');return function(html){div.innerHTML = html;var el = div.childNodes[0];div.removeChild(el);return el;}}();function hasClass(ele,cls){return ele.className.match(new RegExp('(\\s|^)' cls '(\\s|$)'));}function addClass(ele,cls) {if (!hasClass(ele,cls)) ele.className = " " cls;}function removeClass(ele,cls) {var reg = new RegExp('(\\s|^)' cls '(\\s|$)');ele.className=ele.className.replace(reg,' ');}// getOffset function copied from jQuery lib (http://jquery.com/)if (document.documentElement["getBoundingClientRect"]){// Get Offset using getBoundingClientRect// http://ejohn.org/blog/getboundingclientrect-is-awesome/var getOffset = function(el){var box = el.getBoundingClientRect(),doc = el.ownerDocument,body = doc.body,docElem = doc.documentElement,// for ie clientTop = docElem.clientTop || body.clientTop || 0,clientLeft = docElem.clientLeft || body.clientLeft || 0,// In Internet Explorer 7 getBoundingClientRect property is treated as physical,// while others are logical. Make all logical, like in IE8.zoom = 1;if (body.getBoundingClientRect) {var bound = body.getBoundingClientRect();zoom = (bound.right - bound.left)/body.clientWidth;}if (zoom > 1){clientTop = 0;clientLeft = 0;}var top = box.top/zoom (window.pageYOffset || docElem && docElem.scrollTop/zoom || body.scrollTop/zoom) - clientTop,left = box.left/zoom (window.pageXOffset|| docElem && docElem.scrollLeft/zoom || body.scrollLeft/zoom) - clientLeft;return {top: top,left: left};}} else {// Get offset adding all offsets var getOffset = function(el){if (w.jQuery){return jQuery(el).offset();}var top = 0, left = 0;do {top = el.offsetTop || 0;left = el.offsetLeft || 0;}while (el = el.offsetParent);return {left: left,top: top};}}function getBox(el){var left, right, top, bottom;var offset = getOffset(el);left = offset.left;top = offset.top;right = left el.offsetWidth;bottom = top el.offsetHeight;return {left: left,right: right,top: top,bottom: bottom};}/** * Crossbrowser mouse coordinates */function getMouseCoords(e){// pageX/Y is not supported in IE// http://www.quirksmode.org/dom/w3c_cssom.htmlif (!e.pageX && e.clientX){// In Internet Explorer 7 some properties (mouse coordinates) are treated as physical,// while others are logical (offset).var zoom = 1;var body = document.body;if (body.getBoundingClientRect) {var bound = body.getBoundingClientRect();zoom = (bound.right - bound.left)/body.clientWidth;}return {x: e.clientX / zoom d.body.scrollLeft d.documentElement.scrollLeft,y: e.clientY / zoom d.body.scrollTop d.documentElement.scrollTop};}return {x: e.pageX,y: e.pageY};}/** * Function generates unique id */var getUID = function(){var id = 0;return function(){return 'ValumsAjaxUpload' id ;}}();function fileFromPath(file){return file.replace(/.*(\/|\\)/, "");}function getExt(file){return (/[.]/.exec(file)) ? /[^.] $/.exec(file.toLowerCase()) : '';}// Please use AjaxUpload , Ajax_upload will be removed in the next versionAjax_upload = AjaxUpload = function(button, options){if (button.jquery){// jquery object was passedbutton = button[0];} else if (typeof button == "string" && /^#.*/.test(button)){button = button.slice(1);}button = get(button);this._input = null;this._button = button;this._disabled = false;this._submitting = false;// Variable changes to true if the button was clicked// 3 seconds ago (requred to fix Safari on Mac error)this._justClicked = false;this._parentDialog = d.body;if (window.jQuery && jQuery.ui && jQuery.ui.dialog){var parentDialog = jQuery(this._button).parents('.ui-dialog');if (parentDialog.length){this._parentDialog = parentDialog[0];}}this._settings = {// Location of the server-side upload scriptaction: 'upload.php',// File upload namename: 'userfile',// Additional data to senddata: {},// Submit file as soon as it's selectedautoSubmit: true,// The type of data that you're expecting back from the server.// Html and xml are detected automatically.// Only useful when you are using json data as a response.// Set to "json" in that case. responseType: false,// When user selects a file, useful with autoSubmit disabledonChange: function(file, extension){},// Callback to fire before file is uploaded// You can return false to cancel uploadonSubmit: function(file, extension){},// Fired when file upload is completed// WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE!onComplete: function(file, response) {}};// Merge the users options with our defaultsfor (var i in options) {this._settings[i] = options[i];}this._createInput();this._rerouteClicks();}// assigning methods to our classAjaxUpload.prototype = {setData : function(data){this._settings.data = data;},disable : function(){this._disabled = true;},enable : function(){this._disabled = false;},// removes ajaxuploaddestroy : function(){if(this._input){if(this._input.parentNode){this._input.parentNode.removeChild(this._input);}this._input = null;}},/** * Creates invisible file input above the button */_createInput : function(){var self = this;var input = d.createElement("input");input.setAttribute('type', 'file');input.setAttribute('name', this._settings.name);var styles = {'position' : 'absolute','margin': '-5px 0 0 -175px','padding': 0,'width': '220px','height': '30px','fontSize': '14px','opacity': 0,'cursor': 'pointer','display' : 'none','zIndex' : 2147483583 //Max zIndex supported by Opera 9.0-9.2x // Strange, I expected 2147483647};for (var i in styles){input.style[i] = styles[i];}// Make sure that element opacity exists// (IE uses filter instead)if ( ! (input.style.opacity === "0")){input.style.filter = "alpha(opacity=0)";}this._parentDialog.appendChild(input);addEvent(input, 'change', function(){// get filename from inputvar file = fileFromPath(this.value);if(self._settings.onChange.call(self, file, getExt(file)) == false ){return;}// Submit form when value is changedif (self._settings.autoSubmit){self.submit();}});// Fixing problem with Safari// The problem is that if you leave input before the file select dialog opens// it does not upload the file.// As dialog opens slowly (it is a sheet dialog which takes some time to open)// there is some time while you can leave the button.// So we should not change display to none immediatelyaddEvent(input, 'click', function(){self.justClicked = true;setTimeout(function(){// we will wait 3 seconds for dialog to openself.justClicked = false;}, 3000);});this._input = input;},_rerouteClicks : function (){var self = this;// IE displays 'access denied' error when using this method// other browsers just ignore click()// addEvent(this._button, 'click', function(e){// self._input.click();// });var box, dialogOffset = {top:0, left:0}, over = false;addEvent(self._button, 'mouseover', function(e){if (!self._input || over) return;over = true;box = getBox(self._button);if (self._parentDialog != d.body){dialogOffset = getOffset(self._parentDialog);}});// we can't use mouseout on the button,// because invisible input is over itaddEvent(document, 'mousemove', function(e){var input = self._input;if (!input || !over) return;if (self._disabled){removeClass(self._button, 'hover');input.style.display = 'none';return;}var c = getMouseCoords(e);if ((c.x >= box.left) && (c.x <= box.right) && (c.y >= box.top) && (c.y <= box.bottom)){input.style.top = c.y - dialogOffset.top 'px';input.style.left = c.x - dialogOffset.left 'px';input.style.display = 'block';addClass(self._button, 'hover');} else {// mouse left the buttonover = false;if (!self.justClicked){input.style.display = 'none';}removeClass(self._button, 'hover');}});},/** * Creates iframe with unique name */_createIframe : function(){// unique name// We cannot use getTime, because it sometimes return// same value in safari :(var id = getUID();// Remove ie6 "This page contains both secure and nonsecure items" prompt // http://tinyurl.com/77w9whvar iframe = toElement('<iframe src="javascript:false;" name="' id '" />');iframe.id = id;iframe.style.display = 'none';d.body.appendChild(iframe);return iframe;},/** * Upload file without refreshing the page */submit : function(){var self = this, settings = this._settings;if (this._input.value === ''){// there is no filereturn;}// get filename from inputvar file = fileFromPath(this._input.value);// execute user eventif (! (settings.onSubmit.call(this, file, getExt(file)) == false)) {// Create new iframe for this submissionvar iframe = this._createIframe();// Do not submit if user function returns falsevar form = this._createForm(iframe);form.appendChild(this._input);form.submit();d.body.removeChild(form);form = null;this._input = null;// create new inputthis._createInput();var toDeleteFlag = false;addEvent(iframe, 'load', function(e){if (// For Safariiframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" ||// For FF, IEiframe.src == "javascript:'<html></html>';"){// First time around, do not delete.if( toDeleteFlag ){// Fix busy state in FF3setTimeout( function() {d.body.removeChild(iframe);}, 0);}return;}var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;// fixing Opera 9.26if (doc.readyState && doc.readyState != 'complete'){// Opera fires load event multiple times// Even when the DOM is not ready yet// this fix should not affect other browsersreturn;}// fixing Opera 9.64if (doc.body && doc.body.innerHTML == "false"){// In Opera 9.64 event was fired second time// when body.innerHTML changed from false // to server response approx. after 1 secreturn;}var response;if (doc.XMLDocument){// response is a xml document IE propertyresponse = doc.XMLDocument;} else if (doc.body){// response is html document or plain textresponse = doc.body.innerHTML;if (settings.responseType && settings.responseType.toLowerCase() == 'json'){// If the document was sent as 'application/javascript' or// 'text/javascript', then the browser wraps the text in a <pre>// tag and performs html encoding on the contents. In this case,// we need to pull the original text content from the text node's// nodeValue property to retrieve the unmangled content.// Note that IE6 only understands text/htmlif (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE'){response = doc.body.firstChild.firstChild.nodeValue;}if (response) {response = window["eval"]("(" response ")");} else {response = {};}}} else {// response is a xml documentvar response = doc;}settings.onComplete.call(self, file, response);// Reload blank page, so that reloading main page// does not re-submit the post. Also, remember to// delete the frametoDeleteFlag = true;// Fix IE mixed content issueiframe.src = "javascript:'<html></html>';"; });} else {// clear input to allow user to select same file// Doesn't work in IE6// this._input.value = '';d.body.removeChild(this._input);this._input = null;// create new inputthis._createInput();}},/** * Creates form, that will be submitted to iframe */_createForm : function(iframe){var settings = this._settings;// method, enctype must be specified here// because changing this attr on the fly is not allowed in IE 6/7var form = toElement('<form method="post" enctype="multipart/form-data"></form>');form.style.display = 'none';form.action = settings.action;form.target = iframe.name;d.body.appendChild(form);// Create hidden input element for each data keyfor (var prop in settings.data){var el = d.createElement("input");el.type = 'hidden';el.name = prop;el.value = settings.data[prop];form.appendChild(el);}return form;}};})();
评论